// 题目描述：
// 将一个给定字符串 s 根据给定的行数 numRows ，以从上往下、从左到右进行 Z 字形排列。

// 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时，排列如下：

// P   A   H   N
// A P L S I I G
// Y   I   R
// 之后，你的输出需要从左往右逐行读取，产生出一个新的字符串，比如："PAHNAPLSIIGYIR"。

// 请你实现这个将字符串进行指定行数变换的函数：

// string convert(string s, int numRows);


// 示例 1：

// 输入：s = "PAYPALISHIRING", numRows = 3
// 输出："PAHNAPLSIIGYIR"
// 示例 2：
// 输入：s = "PAYPALISHIRING", numRows = 4
// 输出："PINALSIGYAHRPI"
// 解释：
// P     I    N
// A   L S  I G
// Y A   H R
// P     I
// 示例 3：

// 输入：s = "A", numRows = 1
// 输出："A"

// 自己的答案（想不出来）：

// Gpt答案（主要看这个，下面的太复杂了没看过）：
// 理解问题：
// 首先，我明确了问题的输入和输出。输入是一个字符串和一个整数（表示行数），输出是一个新的字符串。
// 接着，我理解了Z字形排列的规则：字符从上到下排列，到达底部后反转方向，从下到上排列，直到达到顶部，然后再次反转方向。这个过程在每一列都会重复。
// 模式识别：
// 我意识到这个问题可以看作是一个二维数组的填充问题。每一行对应Z字形排列中的一行，而二维数组的列则不是固定的，因为Z字形会导致字符在行之间“跳跃”。
// 但是，我可以先假设有一个足够宽的二维数组来容纳所有字符，然后在填充时按照Z字形的规则来更新当前行号。
// 已有知识应用：
// 我知道JavaScript中有数组这种数据结构，可以用来模拟二维数组。
// 我也知道字符串可以通过遍历其字符来逐个处理。
// 另外，我还知道JavaScript提供了一些数组方法，比如push()来向数组添加元素，以及flat()和join()来将二维数组转换为一维字符串。
// 构思算法：
// 基于上述理解，我构思了一个算法：
// a. 创建一个长度为numRows的二维数组，每个元素初始化为空数组。
// b. 遍历输入字符串的每个字符，使用两个变量（currRow和goingDown）来跟踪当前字符应该放在哪一行以及移动方向。
// c. 根据Z字形的规则更新currRow和goingDown。
// d. 将每个字符添加到对应的行中。
// 最后，将二维数组转换为一维字符串作为输出。
// 优化和测试：
// 在实现算法后，我考虑了一些边界情况，比如当numRows为1或字符串长度小于等于numRows时，直接返回原字符串。
// 我也进行了测试，确保算法在不同输入下都能正确工作。
function convert(s, numRows) {
    if (numRows <= 1 || s.length <= numRows) {
        return s;
    }

    const rows = [];
    for (let i = 0; i < numRows; i++) {
        rows.push([]);
    }

    let currRow = 0;
    let goingDown = false;

    for (const char of s) {
        rows[currRow].push(char);
        if (currRow === 0 || currRow === numRows - 1) {
            goingDown = !goingDown;
        }
        currRow += goingDown ? 1 : -1;
    }

    return rows.flat().join('');
}

// 示例测试
console.log(convert("PAYPALISHIRING", 3)); // 输出: "PAHNAPLSIIGYIR"
// [
//     [ 'P', 'A', 'H', 'N' ],
//     [
//       'A', 'P', 'L',
//       'S', 'I', 'I',
//       'G'
//     ],
//     [ 'Y', 'I', 'R' ]
//   ]
console.log(convert("PAYPALISHIRING", 4)); // 输出: "PINALSIGYAHRPI"
// [
//     [ 'P', 'I', 'N' ],
//     [ 'A', 'L', 'S', 'I', 'G' ],
//     [ 'Y', 'A', 'H', 'R' ],
//     [ 'P', 'I' ]
//   ]
console.log(convert("A", 1)); // 输出: "A"

// 官方题解：
var convert = function (s, numRows) {
    const n = s.length,
        r = numRows;
    if (r === 1 || r >= n) {
        return s;
    }
    const t = r * 2 - 2;
    const c = Math.floor((n + t - 1) / t) * (r - 1);
    const mat = new Array(r).fill(0).map(() => new Array(c).fill(0));
    for (let i = 0, x = 0, y = 0; i < n; ++i) {
        mat[x][y] = s[i];
        if (i % t < r - 1) {
            ++x; // 向下移动
        } else {
            --x;
            ++y; // 向右上移动
        }
    }
    const ans = [];
    for (const row of mat) {
        for (const ch of row) {
            if (ch !== 0) {
                ans.push(ch);
            }
        }
    }
    return ans.join('');
};

/**
 * @param {string} s
 * @param {number} numRows
 * @return {string}
 */
var convert = function (s, numRows) {
    if (numRows == 1)
        return s;

    const len = Math.min(s.length, numRows);
    const rows = [];
    for (let i = 0; i < len; i++) rows[i] = "";
    let loc = 0;
    let down = false;

    for (const c of s) {
        rows[loc] += c;
        if (loc == 0 || loc == numRows - 1)
            down = !down;
        loc += down ? 1 : -1;
    }

    let ans = "";
    for (const row of rows) {
        ans += row;
    }
    return ans;
};